Išsamus įdėtųjų objektų serializavimo vadovas Django REST Framework (DRF) naudojant serializatorius, apimantis įvairius ryšių tipus ir pažangias technikas.
Python DRF Serializer santykiai: įvaldykite įdėtųjų objektų serializavimą
Django REST Framework (DRF) suteikia galingą ir lanksčią sistemą žiniatinklio API kūrimui. Svarbus API kūrimo aspektas yra ryšių tarp duomenų modelių tvarkymas, o DRF serializatoriai siūlo patikimus mechanizmus įdėtųjų objektų serializavimui ir deserializavimui. Šis vadovas nagrinėja įvairius būdus, kaip valdyti ryšius DRF serializatoriuose, pateikiant praktinių pavyzdžių ir geriausios praktikos.
Serializer santykių supratimas
Reliacinių duomenų bazėse ryšiai apibrėžia, kaip skirtingos lentelės ar modeliai yra susiję. DRF serializatoriai turi atspindėti šiuos ryšius, kai duomenų bazės objektus konvertuoja į JSON ar kitus duomenų formatus, skirtus API vartojimui. Aptarsime tris pagrindinius ryšių tipus:
- ForeignKey (Vienas-su-daugeliu): Vienas objektas yra susijęs su keliais kitais objektais. Pavyzdžiui, vienas autorius gali parašyti daug knygų.
- ManyToManyField (Daugelis-su-daugeliu): Keli objektai yra susiję su keliais kitais objektais. Pavyzdžiui, keli autoriai gali bendradarbiauti kuriant kelias knygas.
- OneToOneField (Vienas-su-vienu): Vienas objektas yra unikaliai susijęs su kitu objektu. Pavyzdžiui, vartotojo profilis dažnai yra susietas vienas-su-vienu su vartotojo paskyra.
Pagrindinis įdėtųjų serializavimas su ForeignKey
Pradėkime nuo paprasto ForeignKey ryšio serializavimo pavyzdžio. Apsvarstykite šiuos modelius:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
country = models.CharField(max_length=50, default='USA') # Pridėtas šalies laukas tarptautiniam kontekstui
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
publication_date = models.DateField()
def __str__(self):
return self.title
Norėdami serializuoti `Book` modelį su susijusiais `Author` duomenimis, galime naudoti įdėtąjį serializatorių:
from rest_framework import serializers
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ['id', 'name', 'country']
class BookSerializer(serializers.ModelSerializer):
author = AuthorSerializer(read_only=True) # Pakeista iš PrimaryKeyRelatedField
class Meta:
model = Book
fields = ['id', 'title', 'author', 'publication_date']
Šiame pavyzdyje `BookSerializer` apima `AuthorSerializer` lauką. `read_only=True` padaro `author` lauką tik skaitomu, užkertant kelią autoriaus modifikavimui per knygos galinį punktą. Jei jums reikia sukurti arba atnaujinti knygas su autoriaus informacija, turėsite tvarkyti rašymo operacijas kitaip (žr. žemiau).
Dabar, kai serializuojate `Book` objektą, JSON išvestis apims visas autoriaus detales, įdėtas į knygos duomenis:
{
"id": 1,
"title": "Stopas autostopu po galaktiką",
"author": {
"id": 1,
"name": "Douglas Adams",
"country": "UK"
},
"publication_date": "1979-10-12"
}
ManyToManyFiel santykių serializavimas
Apsvarstykime `ManyToManyField` ryšį. Tarkime, kad turime `Category` modelį, o knyga gali priklausyti kelioms kategorijoms.
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
categories = models.ManyToManyField(Category, related_name='books')
publication_date = models.DateField()
def __str__(self):
return self.title
Mes galime serializuoti kategorijas naudodami `serializers.StringRelatedField` arba `serializers.PrimaryKeyRelatedField`, arba sukurti įdėtąjį serializatorių.
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name']
class BookSerializer(serializers.ModelSerializer):
author = AuthorSerializer(read_only=True)
categories = CategorySerializer(many=True, read_only=True) # many=True yra būtinas ManyToManyField
class Meta:
model = Book
fields = ['id', 'title', 'author', 'categories', 'publication_date']
Argumentas `many=True` yra labai svarbus serializuojant `ManyToManyField`. Tai serializatoriui sako, kad tikėtis kategorijų objektų sąrašo. Išvestis atrodys taip:
{
"id": 1,
"title": "Puikybė ir prietarai",
"author": {
"id": 2,
"name": "Jane Austen",
"country": "UK"
},
"categories": [
{
"id": 1,
"name": "Klasikinė literatūra"
},
{
"id": 2,
"name": "Romantika"
}
],
"publication_date": "1813-01-28"
}
OneToOneField santykių serializavimas
Esant `OneToOneField` santykiams, požiūris yra panašus į ForeignKey, tačiau svarbu tvarkyti atvejus, kai susijęs objektas gali neegzistuoti.
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
bio = models.TextField(blank=True)
location = models.CharField(max_length=100, blank=True, default='Global') # Pridėta vieta tarptautiniam kontekstui
def __str__(self):
return self.user.username
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['id', 'bio', 'location']
class UserSerializer(serializers.ModelSerializer):
profile = UserProfileSerializer(read_only=True)
class Meta:
model = User
fields = ['id', 'username', 'email', 'profile']
Išvestis būtų:
{
"id": 1,
"username": "johndoe",
"email": "john.doe@example.com",
"profile": {
"id": 1,
"bio": "Programinės įrangos inžinierius.",
"location": "Londonas, JK"
}
}
Rašymo operacijų tvarkymas (kūrimas ir atnaujinimas)
Aukščiau pateikti pavyzdžiai daugiausia dėmesio skiria tik skaitymui skirtam serializavimui. Norėdami leisti kurti ar atnaujinti susijusius objektus, turite perrašyti `create()` ir `update()` metodus savo serializatoriuje.
Įdėtųjų objektų kūrimas
Tarkime, kad norite sukurti naują knygą ir autorių vienu metu.
class BookSerializer(serializers.ModelSerializer):
author = AuthorSerializer()
class Meta:
model = Book
fields = ['id', 'title', 'author', 'publication_date']
def create(self, validated_data):
author_data = validated_data.pop('author')
author = Author.objects.create(**author_data)
book = Book.objects.create(author=author, **validated_data)
return book
Metode `create()` ištraukiame autoriaus duomenis, sukuriame naują `Author` objektą, o tada sukuriame `Book` objektą, susiedami jį su naujai sukurtu autoriumi.
Svarbu: Turėsite tvarkyti galimas validavimo klaidas `author_data`. Galite naudoti try-except bloką ir sukelti `serializers.ValidationError`, jei autoriaus duomenys yra neteisingi.
Įdėtųjų objektų atnaujinimas
Panašiai, norint atnaujinti tiek knygą, tiek jos autorių:
class BookSerializer(serializers.ModelSerializer):
author = AuthorSerializer()
class Meta:
model = Book
fields = ['id', 'title', 'author', 'publication_date']
def update(self, instance, validated_data):
author_data = validated_data.pop('author', None)
if author_data:
author = instance.author
for attr, value in author_data.items():
setattr(author, attr, value)
author.save()
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
return instance
Metode `update()` atgauname esamą autorių, atnaujiname jo atributus pagal pateiktus duomenis, o tada atnaujiname knygos atributus. Jei `author_data` nepateikiami (tai reiškia, kad autorius neatnaujinamas), kodas praleidžia autoriaus atnaujinimo dalį. Numatytasis `None` reikšmė `validated_data.pop('author', None)` yra labai svarbi tvarkant atvejus, kai autoriaus duomenys nėra įtraukti į atnaujinimo užklausą.
`PrimaryKeyRelatedField` naudojimas
Vietoj įdėtųjų serializatorių galite naudoti `PrimaryKeyRelatedField`, kad atspindėtumėte ryšius naudodami susijusio objekto pirminį raktą. Tai naudinga, kai jums reikia tik nurodyti susijusio objekto ID ir nenorite serializuoti viso objekto.
class BookSerializer(serializers.ModelSerializer):
author = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all())
class Meta:
model = Book
fields = ['id', 'title', 'author', 'publication_date']
Dabar lauke `author` bus autoriaus ID:
{
"id": 1,
"title": "1984",
"author": 3, // Autoriaus ID
"publication_date": "1949-06-08"
}
Norėdami sukurti ir atnaujinti, turėtumėte perduoti autoriaus ID užklausos duomenyse. `queryset=Author.objects.all()` užtikrina, kad pateiktas ID egzistuoja duomenų bazėje.
`HyperlinkedRelatedField` naudojimas
`HyperlinkedRelatedField` atspindi ryšius naudojant hipersaitus į susijusio objekto API galinį punktą. Tai įprasta hipermedijos API (HATEOAS).
class BookSerializer(serializers.ModelSerializer):
author = serializers.HyperlinkedRelatedField(view_name='author-detail', read_only=True)
class Meta:
model = Book
fields = ['id', 'title', 'author', 'publication_date']
Argumentas `view_name` nurodo rodinio, kuris tvarko užklausas susijusiam objektui, pavadinimą (pvz., `author-detail`). Jums reikės apibrėžti šį rodinį savo `urls.py`.
Išvestis apims URL, nukreipiantį į autoriaus išsamios informacijos galinį punktą:
{
"id": 1,
"title": "Puikus naujas pasaulis",
"author": "http://example.com/api/authors/4/",
"publication_date": "1932-01-01"
}
Pažangios technikos ir aspektai
- `depth` parinktis: `ModelSerializer` galite naudoti `depth` parinktį, kad automatiškai sukurtumėte įdėtus serializatorius ForeignKey ryšiams iki tam tikro gylio. Tačiau naudojant `depth` gali kilti našumo problemų, jei ryšiai yra sudėtingi, todėl paprastai rekomenduojama apibrėžti serializatorius aiškiai.
- `SerializerMethodField`: Naudokite `SerializerMethodField`, kad sukurtumėte pasirinktinę serializavimo logiką susijusiems duomenims. Tai naudinga, kai jums reikia formatuoti duomenis konkrečiu būdu arba įtraukti apskaičiuotas reikšmes. Pavyzdžiui, galite rodyti visą autoriaus vardą skirtinga tvarka pagal lokalę. Daugelyje Azijos kultūrų pavardė eina prieš vardą.
- Atvaizdavimo tinkinimas: Perrašykite metodą `to_representation()` savo serializatoriuje, kad tinkintumėte, kaip atvaizduojami susiję duomenys.
- Našumo optimizavimas: Esant sudėtingiems ryšiams ir dideliems duomenų rinkiniams, naudokite tokias technikas kaip select_related ir prefetch_related, kad optimizuotumėte duomenų bazės užklausas ir sumažintumėte duomenų bazės hitų skaičių. Tai ypač svarbu API, aptarnaujantiems pasaulinius vartotojus, kurie gali turėti lėtesnius ryšius.
- Null reikšmių tvarkymas: Atminkite, kaip null reikšmės tvarkomos jūsų serializatoriuose, ypač kai dirbate su pasirenkamais ryšiais. Jei reikia, naudokite `allow_null=True` savo serializatoriaus laukuose.
- Validavimas: Įdiekite patikimą validavimą, kad užtikrintumėte duomenų vientisumą, ypač kuriant ar atnaujinant susijusius objektus. Apsvarstykite galimybę naudoti pasirinktinius validatorius, kad įgyvendintumėte verslo taisykles. Pavyzdžiui, knygos publikavimo data neturėtų būti ateityje.
- Internacionalizacija ir lokalizacija (i18n/l10n): Apsvarstykite, kaip jūsų duomenys bus rodomi skirtingomis kalbomis ir regionuose. Formatuokite datas, skaičius ir valiutas atitinkamai pagal vartotojo lokalę. Saugokite internacionalizuojamas eilutes savo modeliuose ir serializatoriuose.
Geriausia serializatorių santykių praktika
- Išlaikykite serializatorius sufokusuotus: Kiekvienas serializatorius turėtų būti atsakingas už konkretaus modelio arba glaudžiai susijusių duomenų rinkinio serializavimą. Venkite kurti pernelyg sudėtingus serializatorius.
- Naudokite aiškius serializatorius: Venkite per daug pasikliauti `depth` parinktimi. Apibrėžkite aiškius serializatorius kiekvienam susijusiam modeliui, kad turėtumėte daugiau kontrolės serializavimo procese.
- Kruopščiai išbandykite: Parašykite vienetinius testus, kad patikrintumėte, ar jūsų serializatoriai teisingai serializuoja ir deserializuoja duomenis, ypač kai dirbate su sudėtingais ryšiais.
- Dokumentuokite savo API: Aiškiai dokumentuokite savo API galinius punktus ir duomenų formatus, kurių jie tikisi ir grąžina. Naudokite tokius įrankius kaip Swagger arba OpenAPI, kad generuotumėte interaktyvią API dokumentaciją.
- Apsvarstykite API versijų kūrimą: Kai jūsų API vystosi, naudokite versijų kūrimą, kad išlaikytumėte suderinamumą su esamais klientais. Tai leidžia jums įvesti esminių pakeitimų nepaveikiant senesnių programų.
- Stebėkite našumą: Stebėkite savo API našumą ir nustatykite bet kokius stringimus, susijusius su serializatorių santykiais. Naudokite profiliavimo įrankius, kad optimizuotumėte duomenų bazės užklausas ir serializavimo logiką.
Išvada
Įvaldyti serializatorių santykius Django REST Framework yra būtina norint kurti patikimas ir efektyvias žiniatinklio API. Supratę skirtingus ryšių tipus ir įvairias DRF serializatoriuose esančias parinktis, galite efektyviai serializuoti ir deserializuoti įdėtus objektus, tvarkyti rašymo operacijas ir optimizuoti savo API našumą. Nepamirškite apsvarstyti internacionalizacijos ir lokalizacijos kurdami savo API, kad užtikrintumėte, jog ji būtų prieinama pasaulinei auditorijai. Kruopštus testavimas ir aiški dokumentacija yra labai svarbūs siekiant užtikrinti ilgalaikį API prižiūrimumą ir naudojimą.